/*
 * This file is part of aion-engine <aion-engine.com>
 *
 * aion-engine is private software: you can redistribute it and or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Private Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aion-engine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with aion-engine.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionengine.gameserver.model.stats.calc.functions;

import com.aionengine.gameserver.model.gameobjects.Item;
import com.aionengine.gameserver.model.items.ItemSlot;
import com.aionengine.gameserver.model.stats.calc.Stat2;
import com.aionengine.gameserver.model.stats.container.StatEnum;
import com.aionengine.gameserver.model.templates.item.ArmorType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author ATracer (based on Mr.Poke EnchantModifier)
 */
public class StatEnchantFunction extends StatAddFunction {

    private static final Logger log = LoggerFactory.getLogger(StatEnchantFunction.class);

    private Item item;

    public StatEnchantFunction(Item owner, StatEnum stat) {
        this.stat = stat;
        this.item = owner;
    }

    @Override
    public final int getPriority() {
        return 30;
    }

    @Override
    public void apply(Stat2 stat) {
        if (!item.isEquipped())
            return;
        int enchantLvl = item.getEnchantLevel();
        if (enchantLvl == 0)
            return;
        if ((item.getEquipmentSlot() & ItemSlot.MAIN_OFF_HAND.getSlotIdMask()) != 0
                || (item.getEquipmentSlot() & ItemSlot.SUB_OFF_HAND.getSlotIdMask()) != 0)
            return;
        stat.addToBase(getEnchantAdditionModifier(item.getEnchantLevel(), stat));
    }

    private int getEnchantAdditionModifier(int enchantLvl, Stat2 stat) {
        if (item.getItemTemplate().isWeapon()) {
            return getWeaponModifiers(enchantLvl);
        } else if (item.getItemTemplate().isArmor()) {
            return getArmorModifiers(enchantLvl, stat);
        }
        return 0;
    }

    private int getWeaponModifiers(int enchantLvl) {
        switch (stat) {
            case MAIN_HAND_POWER:
            case OFF_HAND_POWER:
            case PHYSICAL_ATTACK:
                switch (item.getItemTemplate().getWeaponType()) {
                    case DAGGER_1H:
                    case SWORD_1H:
                        return 2 * enchantLvl;
                    case POLEARM_2H:
                    case SWORD_2H:
                    case BOW:
                        return 4 * enchantLvl;
                    case MACE_1H:
                    case STAFF_2H:
                        return 3 * enchantLvl;
				default:
					break;
                }
                return 0;
            case BOOST_MAGICAL_SKILL:
                switch (item.getItemTemplate().getWeaponType()) {
                    case BOOK_2H:
                    case MACE_1H:
                    case STAFF_2H:
                    case ORB_2H:
                    case GUN_1H:
                    case CANNON_2H:
                    case HARP_2H:
                        return 20 * enchantLvl;
				default:
					break;
                }
                return 0;
            case MAGICAL_ATTACK:
                switch (item.getItemTemplate().getWeaponType()) {
                    case GUN_1H:
                        return 2 * enchantLvl;
                    case BOOK_2H:
                    case ORB_2H:
                        return 3 * enchantLvl;
                    case CANNON_2H:
                    case HARP_2H:
                        return 4 * enchantLvl;
				default:
					break;
                }
                return 0;
            default:
                return 0;
        }
    }

    private int getArmorModifiers(int enchantLvl, Stat2 applyStat) {
        ArmorType armorType = item.getItemTemplate().getArmorType();
        if (armorType == null) {
            log.warn("Missing item ArmorType itemId: " + item.getItemId() + " EquipmentSlot: " + item.getEquipmentSlot() + " playerObjectId: "
                    + applyStat.getOwner().getObjectId());
            return 0;
        }

        int equipmentSlot = (int) (item.getEquipmentSlot() & 0xFFFFFFFF);
        switch (item.getItemTemplate().getArmorType()) {
            case ROBE:
                switch (equipmentSlot) {
                    case 1 << 5:
                    case 1 << 11:
                    case 1 << 4:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return enchantLvl;
                            case MAXHP:
                                return 10 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 2 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 2 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                    case 1 << 12:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 2 * enchantLvl;
                            case MAXHP:
                                return 12 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 3 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 2 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                    case 1 << 3:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 3 * enchantLvl;
                            case MAXHP:
                                return 14 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 4 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 3 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                }
                return 0;
            case LEATHER:
                switch (equipmentSlot) {
                    case 1 << 5:
                    case 1 << 11:
                    case 1 << 4:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 2 * enchantLvl;
                            case MAXHP:
                                return 8 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 2 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 2 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                    case 1 << 12:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 3 * enchantLvl;
                            case MAXHP:
                                return 10 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 3 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 2 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                    case 1 << 3:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 4 * enchantLvl;
                            case MAXHP:
                                return 12 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 4 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 3 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                }
                return 0;
            case CHAIN:
                switch (equipmentSlot) {
                    case 1 << 5:
                    case 1 << 11:
                    case 1 << 4:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 3 * enchantLvl;
                            case MAXHP:
                                return 6 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 2 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 2 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                    case 1 << 12:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 4 * enchantLvl;
                            case MAXHP:
                                return 8 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 3 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 2 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                    case 1 << 3:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 5 * enchantLvl;
                            case MAXHP:
                                return 10 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 4 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 3 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                }
                return 0;
            case PLATE:
                switch (equipmentSlot) {
                    case 1 << 5:
                    case 1 << 11:
                    case 1 << 4:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 4 * enchantLvl;
                            case MAXHP:
                                return 4 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 2 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 2 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                    case 1 << 12:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 5 * enchantLvl;
                            case MAXHP:
                                return 6 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 3 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 2 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                    case 1 << 3:
                        switch (stat) {
                            case PHYSICAL_DEFENSE:
                                return 6 * enchantLvl;
                            case MAXHP:
                                return 8 * enchantLvl;
                            case PHYSICAL_CRITICAL_RESIST:
                                return 4 * enchantLvl;
                            case MAGICAL_DEFEND:
                                return 3 * enchantLvl;
						default:
							break;
                        }
                        return 0;
                }
                return 0;
            case SHIELD:
                switch (stat) {
                    case DAMAGE_REDUCE:
                        float reduceRate = enchantLvl > 10 ? 0.2f : enchantLvl * 0.02f;
                        return Math.round(reduceRate * applyStat.getBase());
                    case BLOCK:
                        if (enchantLvl > 10)
                            return 30 * (enchantLvl - 10);
                        return 0;
				default:
					break;
                }
            default:
                return 0;
        }
    }

}
